package 集合;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/*
public class test1 {
   public static void main(String []args) {
   	//创建集合的旧方法
      Set<String> set = new HashSet<>();
      set.add("A");
      set.add("B");
      set.add("C");
      set = Collections.unmodifiableSet(set);
      System.out.println(set);
      List<String> list = new ArrayList<>();
      list.add("A");
      list.add("B");
      list.add("C");
      list = Collections.unmodifiableList(list);
      System.out.println(list);
      Map<String, String> map = new HashMap<>();
      map.put("A","Apple");
      map.put("B","Boy");
      map.put("C","Cat");
      map = Collections.unmodifiableMap(map);
      System.out.println(map);
      
      //新方法
      //使用java 9，以下方法将添加到List，Set和Map接口以及它们的重载对应物。
      //static <E> List<E> of(E e1, E e2, E e3);
      //static <E> Set<E>  of(E e1, E e2, E e3);
      //static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3);
      //static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)//超过10个，使用...
      //注意：
      //对于List和Set接口，（...）方法被重载为0到10个参数，一个带有var args参数。
      //对于Map接口，（...）方法重载为0到10个参数。
      //如果Map接口的参数超过10个，则可以使用ofEntries（...）方法接受var args参数。
      Set<String> set1 = Set.of("A", "B", "C");      
      System.out.println(set);
      List<String> list1 = List.of("A", "B", "C");
      System.out.println(list);
      Map<String, String> map1 = Map.of("A","Apple","B","Boy","C","Cat");
      System.out.println(map1);
      Map<String, String> map2 = Map.ofEntries (
         new AbstractMap.SimpleEntry<>("A","Apple"),
         new AbstractMap.SimpleEntry<>("B","Boy"),
         new AbstractMap.SimpleEntry<>("C","Cat"));
      System.out.println(map2);
      

   }
}
*/
/*
public class test1 {
   public static void main(String []args) {    
      LogOracle log = new LogOracle();
      log.logInfo("");
      log.logWarn("");
      log.logError("");
      log.logFatal("");
      LogMySql log1 = new LogMySql();
      log1.logInfo("");
      log1.logWarn("");
      log1.logError("");
      log1.logFatal("");
   }
}
final class LogOracle implements Logging {
   @Override
   public void logInfo(String message) {
      getConnection();
      System.out.println("Log Message : " + "INFO");
      closeConnection();
   }
   @Override
   public void logWarn(String message) {
      getConnection();
      System.out.println("Log Message : " + "WARN");
      closeConnection();
   }
   @Override
   public void logError(String message) {
      getConnection();
      System.out.println("Log Message : " + "ERROR");
      closeConnection();
   }
   @Override
   public void logFatal(String message) {
      getConnection();
      System.out.println("Log Message : " + "FATAL");
      closeConnection();
   }
   @Override
   public void getConnection() {
      System.out.println("Open Database connection");
   }
   @Override
   public void closeConnection() {
      System.out.println("Close Database connection");
   }
}
final class LogMySql implements Logging {
   @Override
   public void logInfo(String message) {
      getConnection();
      System.out.println("Log Message : " + "INFO");
      closeConnection();
   }
   @Override
   public void logWarn(String message) {
      getConnection();
      System.out.println("Log Message : " + "WARN");
      closeConnection();
   }
   @Override
   public void logError(String message) {
      getConnection();
      System.out.println("Log Message : " + "ERROR");
      closeConnection();
   }
   @Override
   public void logFatal(String message) {
      getConnection();
      System.out.println("Log Message : " + "FATAL");
      closeConnection();
   }
   @Override
   public void getConnection() {
      System.out.println("Open Database connection");
   }
   @Override
   public void closeConnection() {
      System.out.println("Close Database connection");
   }
}
interface Logging {
   String ORACLE = "Oracle_Database";
   String MYSQL = "MySql_Database";
   void logInfo(String message);
   void logWarn(String message);
   void logError(String message);
   void logFatal(String message);
   void getConnection();
   void closeConnection();
}
*/
/*
Java所有对象的超类 java.lang.Object 有两个非常重要的方法定义:

public boolean equals(Object obj)
public int hashCode()

实践证明这两个方法是非常重要的，特别是用Map存储用户自定义对象时。然而，有些高级开发者也不一定知道如何合适的使用它们。

本文先用示例演示如何使用它们，然后解释 equals()方法和hashCode是如何协同工作。



1. 错误使用方式
下面是一个常见的错误用法:
*/
//import java.util.HashMap;

public class test1 {
    private String color;

    public test1(String color) {
        this.color = color;
    }
    @Override
    public int hashCode(){
       // 此种实现,要求 color值定以后就不得修改
       // 否则同一个物理对象,前后有两个不同的hashCode,逻辑上就是错的。
       //return this.color.length();
       return Objects.hash(color);
       //Objects.hash()静态方法：
       //public static int hash(Object... values) {
       //	return Arrays.hashCode(values);
    	 //}
       //Arrays类：
       //public static int hashCode(Object[] a) {
       //   if (a == null)
       //       return 0;
       //   int result = 1;
       //   for (Object element : a)
       //       result = 31 * result + (element == null ? 0 : element.hashCode());
       //   return result;
       //}
   }
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof test1))
            return false;    
        if (obj == this)
            return true;
        return this.color == ((test1) obj).color;
    }

    public static void main(String[] args) {
        test1 a1 = new test1("green");
        test1 a2 = new test1("red");
        Object aObject;
        //hashMap stores test1 type and its quantity
        HashMap<test1, Integer> m = new HashMap<test1, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new test1("red")));
    }
}
/*
在此示例中，hashMap 已经保存了一个绿色的test1对象，但想（通过程序中的方式）从map获取此对象时，test1 对象并未被找到。

上述代码的输出结果是：null。 但通过断点调试，可以确定此对象已经存在于hashMap中，截图如下：

这里写图片描述



2. 此问题由hashCode()引起
问题的原因是没有重写”hashCode()”方法。

equals()方法与hashCode()的通用协定是：

2.1 如果两个对象相等（equal）,那么必须拥有相同的哈希码（hash code）
2.2 即使两个对象有相同的哈希值（hash code）,他们不一定相等.

Map的核心思想就是可以比线性查找更快。通过散列值（hash）作为键（key）来定位对象的过程分为两步:

在Map内部，存储着一个顶层数组，顶层数组的每个元素指向其他的数组，查找或存储的时候，先根据key对象的hashCode()值计算出数组的索引,然后到这个索引找到所
指向的第二层线性数组，使用equals方法来比较是否有相应的值（以返回或者存储）。

Object 类中的hashCode()默认为每个对象返回不同的int值，因此在上面的例子中，两个相等(equal)的对象,返回了不同的hashCode值。

解决方法是为此类添加hashCode方法，比如，使用color字符串的长度作为示范:

public int hashCode(){
    // 此种实现,要求 color值定以后就不得修改
    // 否则同一个物理对象,前后有两个不同的hashCode,逻辑上就是错的。
    return this.color.length(); 
}

*/

